<?php
// $Id: Form.php 27 2010-11-16 12:49:54Z mjohnson60@gmail.com $


Loader::import('lib', array(
	'FormElement', 
	'ButtonInput', 
	'CheckboxInput', 
	'FieldsetInput', 
	'PasswordInput', 
	'RadioSetInput', 
	'RadioInput', 
	'SelectInput', 
	'SelectOptionInput', 
	'SubmitInput', 
	'TextAreaInput', 
	'TextFieldInput'
));

/**
 * Enter description here ...
 * 
 * @author markjohnson
 * @version 1.0
 * @copyright Copyright (c) 2010, markjohnson
 * @license http://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
 * 
 */
class Form extends FormElement
{
	var $form_id = '';
	
	var $validator = '';
	var $callback = '';
	
	var $method = 'POST';
	var $action = '';
	
	private static $errors = array();

	/**
	 * Enter description here ...
	 * 
	 * @param array $form
	 */
	public function Form($form = array(), $form_id = '')
	{
		$this->type = 'form';
		$this->render = 'form';
		$this->input = FALSE;
		
		if (!empty($form_id))
		{
			$this->form_id = $form_id;
		}
		
		if (!empty($form))
		{
			if (!empty($form['#method']))
			{
				$this->method = $form['#method'];
			}
			
			if (!empty($form['#action']))
			{
				$this->action = $form['#action'];
			}
			
			if (!empty($form['#validator']))
			{
				$this->validator = $form['#validator'];
			}
			
			if (!empty($form['#callback']))
			{
				$this->callback = $form['#callback'];
			}
			
			parent::__construct($form);
		}
		
		foreach ($this->children as $child)
		{
			$child->setForm($this);
		}
	}

	/**
	 * error()
	 * 
	 * Enter description here ...
	 * 
	 * @param unknown_type $name
	 * @param unknown_type $error
	 * @return multitype:|boolean
	 */
	public static function error($name = NULL, $error = '')
	{
		if (isset($name))
		{
			if (!empty($error))
			{
				self::$errors[$name] = $error;
				Athena::setMessage($error, 'error');
			}
			else if (isset(self::$errors[$name]))
			{
				return self::$errors[$name];
			}
			else
			{
				return FALSE;
			}
		}
		
		return self::$errors;
	}

	/*
	public static function getForm($form_id) 
	{
		$form_state = array('storage' => NULL, 'submitted' => FALSE);
		
		$args = func_get_args();
		$cacheable = FALSE;
		
		if (isset($_SESSION['batch_form_state']))
		{
			// We've been redirected here after a batch processing : the form has
			// already been processed, so we grab the post-process $form_state value
			// and move on to form display. See _batch_finished() function.
			$form_state = $_SESSION['batch_form_state'];
			unset($_SESSION['batch_form_state']);
		}
		else
		{
			// If the incoming $_POST contains a form_build_id, we'll check the
			// cache for a copy of the form in question. If it's there, we don't
			// have to rebuild the form to proceed. In addition, if there is stored
			// form_state data from a previous step, we'll retrieve it so it can
			// be passed on to the form processing code.
			if (isset($_POST['form_id']) && $_POST['form_id'] == $form_id && !empty($_POST['form_build_id']))
			{
				$form = Form::getCache($_POST['form_build_id'], $form_state);
			}
			
			// If the previous bit of code didn't result in a populated $form
			// object, we're hitting the form for the first time and we need
			// to build it from scratch.
			if (!isset($form))
			{
				$form_state['post'] = $_POST;
				// Use a copy of the function's arguments for manipulation
				$args_temp = $args;
				$args_temp[0] = &$form_state;
				array_unshift($args_temp, $form_id);
				
				$form = call_user_func_array('drupal_retrieve_form', $args_temp);
				$form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
				$form['#build_id'] = $form_build_id;
				drupal_prepare_form($form_id, $form, $form_state);
				// Store a copy of the unprocessed form for caching and indicate that it
				// is cacheable if #cache will be set.
				$original_form = $form;
				$cacheable = TRUE;
				unset($form_state['post']);
			}
			
			$form['#post'] = $_POST;
			
			// Now that we know we have a form, we'll process it (validating,
			// submitting, and handling the results returned by its submission
			// handlers. Submit handlers accumulate data in the form_state by
			// altering the $form_state variable, which is passed into them by
			// reference.
			drupal_process_form($form_id, $form, $form_state);
			
			if ($cacheable && !empty($form['#cache']))
			{
				// Caching is done past drupal_process_form so #process callbacks can
				// set #cache.
				Form::setCache($form_build_id, $original_form, $form_state);
			}
		}
		
		// Most simple, single-step forms will be finished by this point --
		// drupal_process_form() usually redirects to another page (or to
		// a 'fresh' copy of the form) once processing is complete. If one
		// of the form's handlers has set $form_state['redirect'] to FALSE,
		// the form will simply be re-rendered with the values still in its
		// fields.
		//
		// If $form_state['storage'] or $form_state['rebuild'] has been set
		// and input has been processed, we know that we're in a complex
		// multi-part process of some sort and the form's workflow is NOT
		// complete. We need to construct a fresh copy of the form, passing
		// in the latest $form_state in addition to any other variables passed
		// into drupal_get_form().
		
		if ((!empty($form_state['storage']) || !empty($form_state['rebuild'])) && !empty($form_state['process_input']) && !form_get_errors())
		{
			$form = drupal_rebuild_form($form_id, $form_state, $args);
		}
		
		// If we haven't redirected to a new location by now, we want to
		// render whatever form array is currently in hand.
		return drupal_render_form($form_id, $form);
	}
	*/
	
	/*
	public static function setCache($form_build_id, $form, $form_state) 
	{
		global $user;
		// 6 hours cache life time for forms should be plenty.
		$expire = 21600;
		
		if ($user->uid)
		{
			$form['#cache_token'] = drupal_get_token();
		}
		
		Storage::cacheSet('form_' . $form_build_id, $form, 'cache_form', time() + $expire);
		
		if (!empty($form_state['storage']))
		{
			cache_set('storage_' . $form_build_id, $form_state['storage'], 'cache_form', time() + $expire);
		}
	}
	*/
	
	/**
	 * getCache()
	 * 
	 * Enter description here ...
	 * 
	 * @param unknown_type $form_build_id
	 * @param unknown_type $form_state
	 * @return Ambiguous
	 */
	/*
	public static function getCache($form_build_id, &$form_state) 
	{
		global $user;
		if ($cached = Storage::cacheGet('form_' . $form_build_id, 'cache_form'))
		{
			$form = $cached->data;
			
			if ((isset($form['#cache_token']) && valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid))
			{
				if ($cached = cache_get('storage_' . $form_build_id, 'cache_form'))
				{
					$form_state['storage'] = $cached->data;
				}
				
				return $form;
			}
		}
	}
	*/
	
	/**
	 * Enter description here ...
	 * 
	 * @param string $form_id
	 * @return boolean|Ambigous <NULL, string>
	 */
	public function build(string $form_id = NULL)
	{
		if (empty($this->form_id))
		{
			if (empty($form_id))
			{
				return FALSE;
			}
			else
			{
				$this->form_id = $form_id;
			}
		}
		
		$this->children[] = new HiddenInput('form_id', $this->form_id, unique_id($this->form_id), $this);
		
		if (!empty($this->validator))
		{
			if (is_array($this->validator))
			{
				$validate_value = serialize($this->validator);
				$this->children[] = new HiddenInput('validator', $validate_value, unique_id($this->validator[0] . '-' . $this->validator[1]), $this);
			}
			else
			{
				$this->children[] = new HiddenInput('validator', $this->validator, unique_id($this->validator), $this);
			}
		}
		
		if (!empty($this->callback))
		{
			if (is_array($this->callback))
			{
				$callback_value = serialize($this->callback);
				$this->children[] = new HiddenInput('callback', $callback_value, unique_id($this->callback[0] . '-' . $this->callback[1]), $this);
			}
			else
			{
				$this->children[] = new HiddenInput('callback', $this->callback, unique_id($this->callback), $this);
			}
		}
		
		if (empty($this->id))
		{
			$this->id = unique_id($this->form_id);
		}
		
		$this->prepare();
		
		Storage::cacheSet($this->form_id, $this, 'cache_form');
		
		return $this->compile();
	}

	/**
	 * render()
	 * 
	 * Enter description here ...
	 * 
	 * @return string
	 */
	public function render()
	{
		$action = !empty($this->action) ? 'action="' . $this->action . '" ' : '';
		return '<form ' . $action . ' accept-charset="UTF-8" method="' . $this->method . '" id="' . $this->id . '"' . (empty($this->attributes) ? '' : attributes($this->attributes)) . ">\n" . '<div class="form-wrapper">' . $this->content . "\n</div></form>\n";
	}

	/* 
	 * @see FormElement::_compile()
	 */
	public function _compile()
	{
		return $this->render();
	}

	/**
	 * Redirect the user to a URL after a form has been processed.
	 *
	 * @param $form
	 * An associative array containing the structure of the form.
	 * @param $redirect
	 * An optional value containing the destination path to redirect
	 * to if none is specified by the form.
	 */
	public static function redirect($form, $redirect = NULL)
	{
		$goto = NULL;
		
		if (isset($redirect))
		{
			$goto = $redirect;
		}
		
		if ($goto !== FALSE && isset($form['#redirect']))
		{
			$goto = $form['#redirect'];
		}
		
		if (!isset($goto) || ($goto !== FALSE))
		{
			if (isset($goto))
			{
				if (is_array($goto))
				{
					call_user_func_array(array('Athena', 'redirect'), $goto);
				}
				else
				{
					Athena::redirect($goto);
				}
			}
			
			Athena::redirect($_GET['q']);
		}
	}
}








